LCP 测量的是视口内最大的图像或文本块的渲染时间,是 Core Web Vitals 三大核心指标之一。良好的 LCP 应该在 2.5 秒以内
| 元素类型 | 说明 |
|---|---|
<img> |
包括动画 GIF/PNG(使用首帧呈现时间) |
<svg> 内的 <image> |
SVG 内嵌图像 |
<video> |
使用海报图像或首帧时间(取较早者) |
CSS background-image |
通过 url() 加载的背景图 |
| 文本块 | 包含文本节点的块级元素 |
排除的元素:
opacity: 0 的不可见元素可见大小 = 视口内可见部分的面积
| 场景 | 计算方式 |
|---|---|
| 图片 | min(可见大小, 原始大小) |
| 文本 | 能包含所有文本节点的最小矩形 |
| 超出视口 | 只计算视口内的部分 |
| CSS 装饰 | margin/padding/border 不计入 |
页面加载 → 首次绘制 → 持续监听 → 用户交互 → 停止
↓ ↓ ↓
初始LCP 更新LCP 最终LCP
关键触发点:
用户交互会终止 LCP 观察:
| 交互类型 | 说明 |
|---|---|
| keydown | 键盘按键 |
| click | 鼠标点击 |
| scroll | 页面滚动 |
| tap | 触摸屏轻触 |
⚠️ 注意:web-vitals 库中没有监听 scroll,因为滚动可以被程序触发,不够可靠
页面状态变化也会触发最终报告:
visibilitychange → hiddenpagehide 事件const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log({
element: lastEntry.element, // LCP 元素
size: lastEntry.size, // 元素大小
startTime: lastEntry.startTime, // 推荐使用此值作为 LCP
renderTime: lastEntry.renderTime,// 渲染时间(跨域可能为 0)
loadTime: lastEntry.loadTime, // 加载时间
url: lastEntry.url // 图片 URL
});
});
observer.observe({ type: "largest-contentful-paint", buffered: true });
startTime = renderTime || loadTime,建议使用 startTime 因为 renderTime 对跨域资源可能不可用
导航开始
│
├─► 首个内容绘制 (FCP)
│
├─► LCP 候选 #1 (小文本块)
│
├─► LCP 候选 #2 (更大的图片) ← 替换 #1
│
├─► 图片加载完成 → 重新计算大小
│
├─► LCP 候选 #3 (Hero Image) ← 替换 #2
│
└─► 用户点击/滚动 → 停止观察,#3 成为最终 LCP